#pragma once
#include "common.h"

template<int ID>
struct queue_item
{
	typedef typename std::shared_ptr<queue_item> ptr_t;
	queue_item()
		:index_(-1)
	{

	}
	virtual ~queue_item() {}

	void set_index(int index)
	{
		index_ = index;
	}
	int get_index()
	{
		return index_;
	}
private:
	int index_;
};

template<int ID>
class queue_t
{
public:
	typedef queue_item<ID> item_t;

	queue_t ()
	{

	}
	void push_back (typename item_t::ptr_t item)
	{
		assert(item);
		item->set_index(items_.size());
		items_.push_back(item);
	}
	void pop_front ()
	{
		auto item = items_.front();
		erase(item);
	}
	typename item_t::ptr_t front()
	{
		return items_.front();
	}
	typename item_t::ptr_t back()
	{
		return items_.back();
	}
	bool empty()
	{
		return items_.empty();
	}
	std::size_t size()
	{
		return items_.size();
	}
	bool exist(typename item_t::ptr_t item)
	{
		if (items_.empty() || 
			item->get_index() == -1 || 
			item->get_index() >(int) items_.size() -1)
			return false;
		
		return items_[item->get_index()] == item;
	}
	void erase(typename item_t::ptr_t item)
	{
		if (items_.empty() || item->get_index() == -1)
			return;
		if (item->get_index() == items_.size() - 1)
		{
			items_.pop_back();
		}
		else
		{
			auto index_ = item->get_index();
			items_.back()->set_index((int)index_);
			items_[index_] = items_.back();
			items_.pop_back();
			item->set_index(-1);
		}
	}
	void clear ()
	{
		items_.clear ();
	}
	void swap(queue_t<ID> &queue)
	{
		items_.swap(queue.items_);
	}
private:
	std::vector<typename item_t::ptr_t> items_;
};
